package com.sdy.supermarket.biz.service.impl;

import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.sdy.common.model.BizException;
import com.sdy.common.model.PageQuery;
import com.sdy.common.model.PageResult;
import com.sdy.common.utils.Assert;
import com.sdy.common.utils.StringUtil;
import com.sdy.supermarket.biz.model.GsRes;
import com.sdy.supermarket.biz.model.GsUserRes;
import com.sdy.supermarket.biz.mapper.GsUserResMapper;
import com.sdy.supermarket.biz.service.GsResService;
import com.sdy.supermarket.biz.service.GsUserResService;
import com.sdy.mvc.service.impl.BaseServiceImpl;
import com.sdy.usercenter.api.UserQueryApi;
import com.sdy.usercenter.api.dto.UserDTO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.integration.redis.util.RedisLockRegistry;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.stream.Collectors;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author zzq
 * @since 2019-07-24
 */
@Slf4j
@Service
public class GsUserResServiceImpl extends BaseServiceImpl<GsUserRes> implements GsUserResService {
    @Resource
    private GsUserResMapper gsUserResMapper;
    @Autowired
    private GsResService gsResService;
    @Autowired
    private RedisLockRegistry redisLockRegistry;
    @Autowired
    private UserQueryApi queryApi;

    @Override
    public List<GsUserRes> listUserRes(Integer deptId) {
        if (deptId == null) {
            return Collections.emptyList();
        }
        List<GsUserRes> userResList = list(new LambdaQueryWrapper<GsUserRes>()
                .eq(GsUserRes::getDeptId, deptId)
                .eq(GsUserRes::getState, 2)
                .orderByDesc(GsUserRes::getId)
        );
        if (!userResList.isEmpty()) {
            List<GsRes> ownResList = gsResService.list(new LambdaQueryWrapper<GsRes>()
                    .in(GsRes::getId, userResList
                            .stream()
                            .map(GsUserRes::getResId)
                            .collect(Collectors.toList())));
            Map<Integer, GsRes> resMap = new HashMap<>();
            ownResList.forEach(item -> resMap.put(item.getId(), item));
            userResList.forEach(item -> item.setGsRes(resMap.get(item.getResId())));
            userResList = userResList.stream().filter(item -> item.getGsRes() != null).collect(Collectors.toList());
        }
        return userResList;
    }

    @Override
    public List<GsUserRes> get7DaysList() {
        return gsUserResMapper.get7DaysList();
    }

    @Override
    @Transactional(rollbackFor = {Exception.class})
    public int isApproveRes(Integer userId, Integer resId) {
        int updateState = 0;
        GsUserRes isApproval = gsUserResMapper.selectOne(Wrappers.<GsUserRes>lambdaQuery().eq(GsUserRes::getUserId, userId).eq(GsUserRes::getResId, resId));
        if (isApproval != null) {
            updateState = gsUserResMapper.deleteById(isApproval);
        } else {
            Date now = new Date();
            GsUserRes gsUserRes = new GsUserRes().setUserId(userId).setResId(resId).setCommonUse(1).setState(2).setSrcDeptName("机构管理员-应用权限管理-机构管理员授权资源").setCreateTime(now).setUpdateTime(now);
            updateState = gsUserResMapper.insert(gsUserRes);
        }
        return updateState;
    }

    @Override
    @Transactional(rollbackFor = {Exception.class})
    public int oneKeyApproveRes(Integer deptId, Integer resId, String userName, Integer type) throws BizException {
        PageQuery pageQuery = new PageQuery();
        long pageSize = 1000;
        pageQuery.setSize(pageSize);
        pageQuery.setCurrent(1);
        PageResult<UserDTO> pageResult = queryApi.pageUserInDept(pageQuery, deptId, userName, Boolean.TRUE);
        long pages = pageResult.getPages();
        for (int i = 1; i <= pages; i++) {
            pageQuery.setCurrent(i);
            pageResult = queryApi.pageUserInDept(pageQuery, deptId, userName, true);
            List<UserDTO> userList = pageResult.getRecords();
            List<GsUserRes> gsUserRes = gsUserResMapper.selectList(Wrappers.<GsUserRes>lambdaQuery().in(GsUserRes::getUserId,
                    userList.stream().map(userDTO -> userDTO.getId()).collect(Collectors.toList())).eq(GsUserRes::getResId, resId));
            int userApproveRes = setUserApproveRes(type, resId, userList, gsUserRes);
            if (userApproveRes == 0) {
                log.error("GsUserResServiceImpl(一键授权)-批量授权时出现错误");
                throw new BizException("批量授权时出现错误,请重试");
            } else {
                log.info("为用户批量授权成功");
            }
        }
        return 1;
    }

    private int setUserApproveRes(Integer type, Integer resId, List<UserDTO> userList, List<GsUserRes> gsUserRes) throws BizException {
        List<GsUserRes> needUpdateList = new ArrayList<>();
        int updateState = 0;
        if (type == 0) {
            userList.forEach(userDTO -> {
                // 如果查询不到资源列表说明该部门没有拥有该资源的用户
                if (gsUserRes.size() == 0) {
                    Date now = new Date();
                    GsUserRes res = new GsUserRes().setUserId(userDTO.getId()).setResId(resId).setCommonUse(1).setState(2).setSrcDeptName("机构管理员-应用权限管理-机构管理员一键授权资源").setCreateTime(now).setUpdateTime(now);
                    needUpdateList.add(res);
                } else {
                    // 查找出没有拥有资源的用户
                    gsUserRes.forEach(userRes -> {
                        if (!userDTO.getId().equals(userRes.getUserId())) {
                            Date now = new Date();
                            GsUserRes res = new GsUserRes().setUserId(userDTO.getId()).setResId(resId).setCommonUse(1).setState(2).setSrcDeptName("机构管理员-应用权限管理-机构管理员一键授权资源").setCreateTime(now).setUpdateTime(now);
                            needUpdateList.add(res);
                        }
                    });
                }

            });
            Assert.isTrue(needUpdateList.size() == 0, "该部门下的所有用户已经拥有该资源权限");
            // 批量插入没有拥有该资源的用户
            updateState = gsUserResMapper.batchInsert(needUpdateList);
            log.info("批量插入没有资源的用户:" + needUpdateList.size() + "条");
        }
        if (type == 1) {
            // 查找出拥有资源的用户
            userList.forEach(userDTO -> {
                gsUserRes.forEach(userRes -> {
                    if (userDTO.getId().equals(userRes.getUserId())) {
                        GsUserRes res = new GsUserRes().setId(userRes.getId());
                        needUpdateList.add(res);
                    }
                });
            });
            Assert.isTrue(needUpdateList.size() == 0, "该部门下已经没有用户拥有该资源");
            // 批量删除已经拥有权限的用户
            updateState = gsUserResMapper.delete(Wrappers.<GsUserRes>lambdaQuery()
                    .in(GsUserRes::getId, needUpdateList.stream().map(userRes -> userRes.getId()).collect(Collectors.toList())));
            log.info("批量删除已经拥有权限的用户:" + needUpdateList.size() + "条");
        }
        return updateState;
    }

    @Override
    public void applyRes(Integer opUserId, Integer resId, Integer userId) throws BizException, InterruptedException {
        Lock lock = redisLockRegistry.obtain(GsUserResServiceImpl.class.getName());
        if (lock.tryLock(10, TimeUnit.SECONDS)) {
            try {
                GsUserRes originUserRes = lambdaQuery().eq(GsUserRes::getResId, resId).eq(GsUserRes::getUserId, opUserId).one();
                Assert.isNull(originUserRes, "您没有该应用权限。");
                GsUserRes existUserRes = getOne(
                        lambdaQuery().eq(GsUserRes::getResId, resId).eq(GsUserRes::getUserId, userId)
                );
                Assert.notNull(existUserRes, "该用户已有该应用权限。");
                log.info("给用户{}添加资源{}", userId, resId);
                save(new GsUserRes()
                        .setResId(resId)
                        .setUserId(userId)
                        .setCreateTime(new Date())
                        .setCommonUse(0)
                        .setState(2)
                        .setSrcDeptName(""));
            } finally {
                lock.unlock();
            }
        }
    }

    @Override
    public void applyRes(Integer resId, Integer userId) throws BizException, InterruptedException {
        Lock lock = redisLockRegistry.obtain(GsUserResServiceImpl.class.getName());
        if (lock.tryLock(10, TimeUnit.SECONDS)) {
            try {
                GsUserRes existUserRes = lambdaQuery().eq(GsUserRes::getResId, resId).eq(GsUserRes::getUserId, userId).one();
                Assert.notNull(existUserRes, "该用户已有该应用权限。");
                log.info("给用户{}添加资源{}", userId, resId);
                save(new GsUserRes()
                        .setResId(resId)
                        .setUserId(userId)
                        .setCreateTime(new Date())
                        .setCommonUse(0)
                        .setState(2)
                        .setSrcDeptName(""));
            } finally {
                lock.unlock();
            }
        }
    }

    @Override
    public IPage<GsRes> getUserResList(Page<GsRes> page, Integer userId, String resName, Integer state) {
        UserDTO user = queryApi.getUser(userId);
        List<GsUserRes> resList = gsUserResMapper.selectList(Wrappers.<GsUserRes>lambdaQuery().eq(GsUserRes::getDeptId, user.getOwnDeptId()));
        LambdaQueryWrapper<GsRes> wrapper = new LambdaQueryWrapper<>();
        if (StringUtil.isNotBlank(resName) && StringUtil.isNotEmpty(resName)) {
            wrapper.like(GsRes::getName, resName);
        }
        if (state != null) {
            wrapper.eq(GsRes::getState, state);
        }
        IPage<GsRes> iPage = gsResService.page(page, wrapper.in(!resList.isEmpty(), GsRes::getId, resList.stream()
                .filter(res -> res.getResId() != null).map(res -> res.getResId())
                .collect(Collectors.toList())).select(GsRes::getId, GsRes::getDeptId, GsRes::getDeptName, GsRes::getName, GsRes::getState, GsRes::getResSource)
                .orderByDesc(GsRes::getId));
        return iPage;
    }

    @Override
    public void setCommonRes(Integer userId, Integer resId, Integer type) {
        lambdaUpdate()
                .eq(GsUserRes::getUserId, userId)
                .eq(GsUserRes::getResId, resId)
                .set(GsUserRes::getCommonUse, type)
                .update();
    }

}
